#!/usr/bin/env python

import shutil, os, urllib, sys
from os3.utils.image_handler import ImageHandler


class MediaManagerHandler ( object ):
	TEMPLATES = {
		"image" : '<img src="/site/media_manager/image/__MM_SIZE__/%(id_media)s__MM_EXT__" alt="" border="0" />',

		"flash" : """<object width="" height="" >
                        <param name="movie" value="/site/media_manager/flash/orig/%(id_media)s.swf"></param>
                        <param name="allowFullScreen" value="true"></param>
                        <param name="allowscriptaccess" value="always"></param>
                        <param name="wmode" value="transparent"></param>
                        <embed src="/site/media_manager/flash/orig/%(id_media)s.swf" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="" height=""></embed>
                        </object>""",

		#"youtube" : '<img src="/modules/media_manager/gfx/youtube___MM_SIZE__.gif" alt="" border="0" />'
		"youtube" : '<img src="/site/media_manager/youtube/__MM_SIZE__/%(id_media)s__MM_EXT__" alt="" border="0" />'
	}

	def __init__ ( self, dbm, cfg = None, pyhp = None ):
		self.dbm = dbm
		self.path = "."
		self.ih = ImageHandler ()
		self.pyhp = pyhp
	
		if not cfg:
			cfg = {}

		self.cfg = cfg

		self._image_sizes = (
			( "full",  self.cfg.get ( "image.full.w", 800 ), self.cfg.get ( "image.full.h", 600 ) ),
			( "small", self.cfg.get ( "image.small.w", 400 ), self.cfg.get ( "image.small.h", 300 ) ),
			( "thumb", self.cfg.get ( "image.thumb.w", 200 ), self.cfg.get ( "image.thumb.h", 150 ) ),
			( "icon",  self.cfg.get ( "image.icon.w", 64 ), self.cfg.get ( "image.icon.h", 48 ) ),
		)

	def add_image ( self, module, id_obj, descr, file_obj, pos = 0 ):
		id_media, fname = self._save_orig ( "image", file_obj, module, id_obj, descr, pos )

		self._save_img ( "image", fname, module, id_obj, descr, pos, id_media = id_media )

		# Aggiorno il campo ``data``
		# self._update_data ( id_media, "%s" % id_media )

		return id_media

	def get_files ( self, module, id_obj, kind = 'image' ):
		"""
		This method lists all files associated to a specific ``id_obj`` and ``module``.
		By default, the ``kind`` is set to ``image``, but it may be changed to whatever
		media you are storing. 
		Set ``kind`` == '' to get all media associated to the given ``id_obj``.

		The result is a list containing a dictionary with *at* *least* these fields:

			- id_media	- The media id
			- kind		- The media kind (eg. "image", "youtube")
			- ext		- File extension for the current media
			- data		- The media data info

		If the kind is ``image``, you will get more information:

			- size		- Size (in bytes) of the original file
			- md5		- MD5 string rappresentation of the file

		If nothing found, returns an empty list
		"""

		def _get_image_info ( dest_path, img ):
			from hashlib import md5

			fname = os.path.join ( dest_path, "orig", str ( img [ 'id_media' ] ) + img [ 'ext' ] )
			try:
				fin = open ( fname, "rb" ).read ()
				img [ 'size' ] = len ( fin )
				img [ 'md5' ]  = md5 ( fin ).hexdigest ()
			except:
				img [ 'size' ] = 0
				img [ 'md5' ] = "0"


		conds = [ "module = '%s'" % module,
			  "id_obj = '%s'" % id_obj ]

		if kind:
			conds.append ( "kind = '%s'" % kind )
			
		ids = self.dbm.all_rows ( "media_data", [ "id_media", "ext", "kind", "data" ], " AND ".join ( conds ) )
		if not ids:
			return []

		# ``image`` kinds get some more info data back
		dest_path = self._resolve_path ( kind )

		for obj in ids:
			if obj [ 'kind' ] == 'image':
				_get_image_info ( dest_path, obj )
			
		return ids

	def rotate ( self, id_media, direction ):
		from os3.utils.image_handler import ImageHandler

		# Controllo che id_media sia di fatto un'immagine
		vals = self.dbm.single_row ( "media_data", [ "kind", "module", "ext" ], "id_media = %s" % id_media )
		kind = vals [ 'kind' ]
		if kind != "image":
			# TODO: messaggio di errore
			return

		# Risolvo il base path 
		dest_path = self._resolve_path ( kind )

		# Carico l'immagine originale
		fname = os.path.join ( dest_path, "orig", str ( id_media ) + vals [ 'ext' ] )
		ih = ImageHandler ()
		img = ih.load ( fname )

		# La ruoto
		ang = 90
		if direction == "right": ang = -90
		img.toRGB ()
		img.rotate ( ang )

		# Salvo l'immagine originale
		img.save ( fname )

		# Adesso devo creare tutte le altre immagini
		self._save_img ( kind, None, None, 0, None, 0, id_media, img )

		return id_media

	def add_flash ( self, module, id_obj, descr, file_obj, pos = 0 ):
		id_media, fname = self._save_orig ( "flash", file_obj, module, id_obj, descr, pos )
		return id_media

	def add_youtube ( self, module, id_obj, descr, youtube_code, pos = 0 ):
		# Scarico la thumb da youtube in una dir temporanea
		url_full = "http://i3.ytimg.com/vi/%s/0.jpg" % youtube_code
		web_file = urllib.urlopen ( url_full )
		#sys.stderr.write ( " media_manager add_youtube url_full: %s\n " % url_full )
		tmp_name = os.tmpnam ()
		local_file = file ( tmp_name, "w" )
		local_file.write ( web_file.read () )
		web_file.close ()
		local_file.close ()

		# Aggiungo le immagini
		id_media = self._save_img ( "youtube", tmp_name, module, id_obj, descr, pos, data = youtube_code )

		# Se non trovo id_media, c'e' stato un errore, ed esco
		if not id_media: return 0

		# Aggiorno il campo ``data``
		#self._update_data ( id_media, "%s" % youtube_code )

		# Cancello il file temporaneo
		os.unlink ( tmp_name )

		# Restituisco id_media
		return id_media
	
	def _save_orig ( self, kind, file_obj, module, id_obj, descr, pos, data = '' ):
		"""
		file_obj:	The object returned by pyhp.uploads ().
				It is a dictionary full of informations
				like ``file`` (the file handler) and ``filename`` (the original filename)
		"""
		# 0. Prendo l'estensione del file
		ext = os.path.splitext ( file_obj [ 'filename' ] ) [ 1 ].lower ()

		# 1. Alloco un ID nella tabella ``media_data``
		id_media = self._add ( module, id_obj, descr, kind, pos, ext = ext, data = data )

		# 2. Risolvo la dir di destinazione
		dest_path = self._resolve_path ( kind )
		my_path = os.path.join ( dest_path, "orig" )
		self._check_dirs ( my_path )

		# Creo il nome di file definitivo
		fname = os.path.join ( my_path, str ( id_media ) + ext )

		# Leggo il file e  lo scrivo
		fout = open ( fname, "wb" )
		fout.write ( file_obj [ 'file' ].read () )
		fout.close ()

		# Restituisco id_media e fname
		return id_media, fname

	def _save_img ( self, kind, fname, module, id_obj, descr, pos, id_media = 0, img = None, data = '' ):
		if not id_media:
			# 0. Alloco un ID nella tabella ``media_data``
			id_media = self._add ( module, id_obj, descr, kind, pos, data = data )


		# Carico l'immagine con ImageHandler
		if not img:
			img = self.ih.load ( fname )
			if not img: return 0
			if img: img.toRGB ()

		dest_path = self._resolve_path ( kind )

		base_img = img

		for size in self._image_sizes:

			img = base_img.copy ()

			base = size [ 0 ]

			# Scalo l'immagine in dimensone FULL 
			img.scale ( int ( size [ 1 ] ), int ( size [ 2 ] ) )

			my_path = os.path.join ( dest_path, base )
			self._check_dirs ( my_path )

			# Salvo l'immagine FULL nel path definitivo
			img.save ( os.path.join ( my_path, "%s.jpg" % id_media ), "JPEG" )

		return id_media

	def _check_dirs ( self, path ):
		if os.path.isdir ( path ):
			return

		os.makedirs ( path )

	def add_file ( self, module, id_obj, descr, fname, pos = 0, ext = '', kind = 'file', data = '' ):
		# 0. Alloco un ID nella tabella ``media_data``
		id_media = self._add ( module, id_obj, descr, kind, pos, data = data )

		if not ext:
			ext = os.path.splitext ( fname ) [ 1 ]

		if ext [ 0 ] != '.': ext = '.' + ext

		path = self._resolve_path ( kind )
		dest_name = os.path.join ( path, str ( id_media ) + ext )

		print "Copy: %s - %s" % ( fname, dest_name )

		# 1. Copio l'immagine fname nella nuova dir
		shutil.copyfile ( fname, dest_name )
		
		# 3. Aggiorno il campo ``data``
		self._update_data ( id_media, "/site/media_manager/%s/%s%s" % ( kind, str ( id_media ), ext ) )

		return id_media

	def del_media_by_id_obj ( self, id_obj, module = '', kind = '' ):
		"""
		del_media_by_id_obj ( id_obj, module = '', kind = '' )

		Searches ``media_data`` for ``id_obj`` and deletes all ``id_media`` matching
		``id_obj`` and (optionally) ``module`` and ``kind``.

		The method returns the number of rows deleted.

		:SEE ALSO:  
				- del_media ()
		"""
		conds = [ "id_obj = '%s'" % id_obj ]
		if module: conds.append ( "module = '%s'" % module )
		if kind:   conds.append ( "kind = '%s'" % kind )

		# Prendo l'elenco degli id_media
		cur = self.dbm.select ( 'media_data', [ "id_media" ], " AND ".join ( conds ) )
		if not cur: return 0

		count = 0
		for row in cur:
			count += 1
			self.del_media ( row [ 'id_media' ] )

		return count
		

	def del_media ( self, id_media ):
		# Prendo il tipo e id_object
		vals = self.dbm.single_row ( "media_data", [ "kind", "module", "id_obj" ], "id_media = %s" % id_media )
		
		# =====================================================
		# Cancello i file dalle varie dir di preview
		# =====================================================

		# 1. Rimuovo il file
		self._del_media ( id_media, vals )

		# 2. Rimuovo la entry da media_data
		self.dbm.delete ( "media_data", "id_media = '%s'" % id_media )

		return vals [ 'module' ], vals [ 'id_obj' ]

	def _del_media ( self, id_media, vals ):
		# 1. Risolvo il path
		path = self._resolve_path ( vals [ 'kind' ] )

		# 2. Ciclo sulle varie possibili preview
		types = [ s [ 0 ] for s in self._image_sizes ]
		types.append ( 'orig' )

		for base in types:
			final_name = os.path.join ( path, base, "%s.jpg" % id_media )

			# Cancello il file
			self._del_file ( final_name )

	def _del_file ( self, full_name ):
		if os.path.isfile ( full_name ):
			try:
				os.unlink ( full_name )
			except:
				pass

	def add_url ( self, module, id_obj, descr, url, pos = 0, data = '' ):
		# 0. Alloco un ID nella tabella ``media_data``
		id_media = self._add ( module, id_obj, descr, "url", pos, url, data = data )
		return id_media

	def del_items ( self, module, id_obj ):
		ids = self.dbm.all_rows ( "media_data", [ "id_media", "kind" ], "id_obj = '%s' AND module = '%s'" % ( id_obj, module ) )
		if ids:
			for vals in ids:
				self._del_media ( vals [ 'id_media' ], vals )

		self.dbm.delete ( "media_data", "id_obj = '%s' AND module = '%s'" % ( id_obj, module ) )

	def get_items ( self, module, id_obj, order_mode = '' ):
		order = { 
				"data" : "created",
				"data desc" : "created DESC",
				"pos" : "pos",
				"pos desc" : "pos DESC",
				"descr"    : "descr",
				"id"	   : "id_media",
				"id desc"  : "id_media DESC" }.get ( order_mode, "pos" )


		if self.pyhp: self.dbm.debug = self.pyhp.log.debug

		cur = self.dbm.select ( "media_data", [ 'id_media', 'module', 'id_obj', 'kind', 'descr', 'pos', 'created', 'data', 'ext' ], "id_obj = '%s' AND module = '%s'" % ( id_obj, module ), extras = "ORDER BY %s" % order, debug = 0 ) #self.debug () )
		rows = []
	
		sizes = {};
		for size in self._image_sizes:
			sizes [ size [ 0 ] ] = { 'W' : int ( size [ 1 ] ), 'H' : int ( size [ 2 ] ) }
	
		if cur:
			for row in cur:
				templ = self.TEMPLATES.get ( row [ 'kind' ] )

				if not templ: templ = "MISSING TEMPLATE: " + row [ 'kind' ]
				else: templ = templ % row
				row [ 'html' ] = templ.replace ( "__MM_SIZE__", "%(_size)s" ).replace ( "__MM_EXT__", "%(_ext)s" ) 
				rows.append ( row )

		
		return { 'media_items' : rows, 'sizes' : sizes }

	def _add ( self, module, id_obj, descr, kind, pos = 0, ext = '', data = '' ):
		"""
		add ()
		------

		:SYNOPSIS: ``add ( id_obj, descr, kind, pos = 0, ext = '', data = '' ) -> Insert ID (int)``

		:INPUT:
			- module:		The module name
			- id_obj:		The object ID to add the media to.
			- id_media_kind:	The type of media you are adding
			- pos:			Position inside the Object's media
			- ext:			File extension ( if any )
			- data:			Value to save in the ``data`` field

		:RESULT:
			- The insert ID inside the database

		"""
		dct = { "id_obj" : id_obj,
			"descr" : descr,
			"kind" : kind,
			"pos" : pos,
			"module" : module,
			"created" : "*NOW()",
			"ext" : ext,
			"data" : data
		}

		#self.dbm.debug = sys.stderr.write
		self.dbm.insert ( "media_data", dct )
		#self.dbm.debug = None
		last_id = self.dbm.insert_id ()

		if not data: 
			self.dbm.update ( "media_data", { "data" : last_id }, "id_media = '%s'" % last_id )

		return last_id

	def _resolve_path ( self, kind ):
		my_path = os.path.join ( self.path, kind )
		if not os.path.isdir ( my_path ): os.makedirs ( my_path )
		return my_path

	def _update_data ( self, id_media, data ):
		dct = { "data" : data }
		self.dbm.update ( "media_data", dct, "id_media = %s" % id_media )

        def serve_file ( self, kind, mode, id_media, ext ):
		path_name = self._resolve_path ( kind )
		final_name = os.path.join ( path_name, mode, "%s.%s" % ( id_media, ext ) )
                data = open ( final_name, "rb" ).read ()
                #mime = self._define_mime_type ( path_name )

                self.pyhp.set_header (  'Content-Type', "application/octet-stream" ) #mime [ 0 ] )
                # FIXME: i valori devono essere string
                self.pyhp.set_header (  'Content-Length', str ( len ( data ) ) )
                self.pyhp.set_header (  'Content-Transfer-Encoding', "binary" )
                #self.pyhp.set_header (  'Content-Disposition', 'attachment; filename="%s"' % file_name )
